﻿using NCS.IConnect.Core.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Permissions;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using System.Web.Http.ModelBinding;
using System.Web.Http.Results;

namespace NCS.IConnect.Core.WebApi
{
    /// <summary>
    /// A custom <see cref="IActionFilter"/> to make sure all input values are successfully validated.
    /// </summary>
    [ComVisible(false)]
    public class EnsureValidInputAttribute : ActionFilterAttribute
    {
        /// <summary>
        /// A<see cref="bool"/> value indicating whether to validate input.
        /// </summary>
        public bool Enabled { get; set; }

        /// <summary>
        /// Create a new <see cref="EnsureValidInputAttribute"/>.
        /// </summary>
        public EnsureValidInputAttribute()
        {
            this.Enabled = true;
        }

        /// <summary>
        ///  Occurs before the action method is invoked.
        /// </summary>
        /// <param name="actionContext">The action context.</param>
        [EnvironmentPermission(SecurityAction.LinkDemand, Unrestricted = true)]
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            if (this.Enabled && !actionContext.ModelState.IsValid)
            {
                actionContext.Response = actionContext.Request.CreateResponse(
                    HttpStatusCode.BadRequest, this.CreateInvalidModelStateError(actionContext.ModelState));
            }
            base.OnActionExecuting(actionContext);
        }

        private HttpErrorInfo CreateInvalidModelStateError(ModelStateDictionary modelState, bool includeErrorDetail = false)
        {
            return new HttpErrorInfo(Errors.E0005.ErrorCode, Errors.E0005.Message, modelState, includeErrorDetail)
            {
                Remark = Errors.E0005.Remark
            };
        }
        
    }

    /// <summary>
    /// A custom <see cref="ErrorInfo"/> carrying validation error information.
    /// </summary>
    [ComVisible(false)]
    [DataContract(Namespace = Constants.Namespace)]
    public class HttpErrorInfo : ErrorInfo
    {
        /// <summary>
        /// An <see cref="HttpError"/> carrying validation error information.
        /// </summary>
        [DataMember]
        public HttpError Errors { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="HttpErrorInfo" /> class.
        /// </summary>
        /// <param name="errorCode">The error code.</param>
        /// <param name="message">The message.</param>
        /// <param name="modelState"> A <see cref="ModelStateDictionary"/> carrying validation error information.</param>
        /// <param name="includeErrorDetail">true to include exception messages in the error; false otherwise</param>
        public HttpErrorInfo(string errorCode, string message, ModelStateDictionary modelState, bool includeErrorDetail)
            : base(errorCode, message)
        {
            Guard.ArgumentNotNull(modelState, "modelState");
            this.Errors = new HttpError(modelState, includeErrorDetail);
        }
    }
}